<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>VUE组件</title>
</head>
<body>
    <fieldset>
        <legend>
            VUE组件用法
        </legend>
        <p>
            组件(Component)是Vue.js最核心的功能，也是整个框架设计最精彩的地方，当然也是最难掌握的。
            组件需要注册后才可以使用，注册有全局注册和局部注册两种方式，全局注册后， 任何Vue实例都可以使用。
        </p>
        <hr/>
        <div id="app1">
            <my-component></my-component>
        </div>
        <hr/>
        <div id="app2">
            <!--全局注册后，任何Vue实例都可以使用。-->
            <my-component></my-component>
            <!--组件名称必须使用小写字母，如果写成<my-Subcomponent></my-Subcomponent>这样会渲染出错-->
            <my-subcomponent></my-subcomponent>
            <xdp></xdp>
            <nyl></nyl>
        </div>
        <hr/>
        <div id="app3">
            <xdp-gacl></xdp-gacl>
        </div>
        <hr/>
        <div id="app4">
            <!--组件使用了3次，但是点击任意一个<button>, 3个的数字都会加1，那是因为组件的data引用的是外部的对象-->
            <gacl></gacl>
            <gacl></gacl>
            <gacl></gacl>
        </div>
        <hr/>
        <div id="app5">
            <xdp></xdp>
            <xdp></xdp>
            <xdp></xdp>
        </div>
    </fieldset>
    <fieldset>
        <legend>使用props传递数据</legend>
        <p>
            组件不仅仅是要把模板的内容进行复用，更重要的是组件间要进行通信。
            通常父组件的模板中包含子组件，父组件要正向地向子组件传递数据或参数，子组件接收到后根据参数的不同来渲染不同的内容或执行操作。
            这个正向传递数据的过程就是通过props来实现的。
            在组件中，使用选项 props来声明需要从父级接收的数据， props的值可以是两种， 一种是字符串数组，一种是对象
        </p>
        <div id="app6">
            <xdp-component msg="来自父组件的数据" name="孤傲苍狼" age="30"></xdp-component>
        </div>
        <hr/>
        <div id="app7">
            <gacl-component warning-text="警告消息"></gacl-component>
        </div>
        <hr/>
        <div id="app8">
            <!--用v-model 绑定了父级的数据parentMessage，当通过输入框任意输入时，子组件接收到的props "msg"也会实时响应，并更新组件模板。-->
            <input type="text" v-model="parentMessage">
            <nyl-component :msg="parentMessage"></nyl-component>
        </div>
       <fieldset>
           <legend>
               单向数据流
           </legend>
           <p>Vue2.x通过props传递数据是单向的了，也就是父组件数据变化时会传递给子组件，但是反过来不行。之所以这样设计，是尽可能将父子组件解耦，避免子组件无意中修改了父组件的状态。</p>
           <div id="app9">
               <a-component :init-count="1"></a-component>
           </div>
           <div id="app10">
               <b-component :width="100" :height="200" :border-width="1"></b-component>
           </div>
       </fieldset>
        <fieldset>
            <legend>组件通信</legend>
            <p>
                组件通信可分为父子组件通信、兄弟组件通信、跨级组件通信
            </p>
            从父组件向子组件通信，通过props传递数据就可以了，当子组件需要向父组件传递数据时，就要用到自定义事件。

        </fieldset>
    </fieldset>
</body>
</html>
<script src="node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    //注册组件（全局注册），my-component就是注册的组件自定义标签名称，推荐使用小写加减号分割的形式命名。
    //全局注册后，任何Vue实例都可以使用。
    Vue.component("my-component",{
        //template的DOM结构必须被一个元素包含， 如果直接写成“这里是组件的内容”，不带“<div></div>”是无法渲染的。
        template:'<div><h1>这是全局注册的组件的内容</h1></div>'
    });
    var app1 = new Vue({
        el:"#app1"
    });

    var child = {
        template:'<div>局部注册组件的内容</div>'
    };

    var xdpComponent = {
        template:'<div>xdp局部注册组件的内容</div>'
    };
    var nylComponent = {
        template:'<div>nyl局部注册组件的内容</div>'
    };
    var app2 = new Vue({
        el:"#app2",
        components:{
            //注册子组件
            'my-subcomponent':child,
            'xdp':xdpComponent,
            'nyl':nylComponent
        }
    });

    /**
     * 除了template 选项外，组件中还可以像 Vue 实例那样使用其他的选项，比如data、computed 、
     methods等。但是在使用 data 时，和实例稍有区别，data必须是函数，然后将数据return 出去
     */
    Vue.component("xdp-gacl",{
        template:"<div>{{message}}</div>",
        data:function () {
            return {
                message:'xdp-gacl组件内容'
            }
        }
    });

    var app3 = new Vue({
        el:"#app3"
    });

    var data = {
        counter:0
    };

    Vue.component("gacl",{
        template:"<button @click='counter++'>{{counter}}</button>",
        data:function () {
            /**
             * JavaScript 对象是引用关系，所以如果return出 的对象引用了外部的一个对象，
             * 那这个对象就是共享的，任何一方修改都会同步。
             */
            return data;//引用了外部的一个对象
        }
    });

    var app4 = new Vue({
        el:"#app4"
    });

    Vue.component("xdp",{
        template:"<button @click='counter++'>{{counter}}</button>",
        data:function () {
            //给组件返回一个新的data对象来独立，这样，点击3个按钮就互不影响了，完全达到复用的目的。
            return {
                counter:0
            }
        }
    });

    var app5 = new Vue({
        el:"#app5"
    });

    Vue.component("xdp-component",{
        props:['msg','name','age'],
        template:"<div>" +
                    "{{msg}}，" +
                    "名字：{{name}}，" +
                    "年龄：{{age}}" +
                "</div>"
    });

    var app6 = new Vue({
        el:"#app6"
    });

    Vue.component("gacl-component",{
        props:['warningText'],
        template:"<div>{{warningText}}</div>"
    });

    var app7 = new Vue({
        el:"#app7"
    });

    Vue.component("nyl-component",{
        props:['msg'],
        template:"<div>{{msg}}</div>"
    });

    var app8 = new Vue({
        el:'#app8',
        data:{
            parentMessage:''
        }
    });

    Vue.component("a-component",{
        props:['initCount'],
        template:"<div>{{count}}</div>",
        data:function () {
            return {
                /**
                 * 组件中声明了数据count，它在组件初始化时会获取来自父组件的 initCount，之后就与之无关 了，只用维护count，这样就可以避免直接操作initCount。
                 */
                count:this.initCount
            }
        }
    });

    var app9 = new Vue({
        el:"#app9"
    });

    Vue.component("b-component",{
        props:['width','height','borderWidth'],
        template:"<div :style='style'>组件内容</div>",
        computed:{//计算属性
            style: function () {
                return {
                    width:this.width+"px",
                    height:this.height+"px",
                    border:this.borderWidth+"px solid",
                    display:"block"
                }
            }
        }
    });

    var app10 = new Vue({
        el:"#app10"
    });
</script>